package com.ymm.lulutong.domain.impl;

import com.ymm.lulutong.constant.ProfileCodeEnum;
import com.ymm.lulutong.constant.VIPCodeEnum;
import com.ymm.lulutong.domain.ShipperProfileDomainService;

import com.ymm.lulutong.domain.utils.EncryptionUtils;
import com.ymm.lulutong.domain.utils.FormatUtils;
import com.ymm.lulutong.domain.utils.UploadFileUtils;
import com.ymm.lulutong.entity.Shipper;
import com.ymm.lulutong.mapper.ShipperProfileMapper;
import com.ymm.lulutong.utils.Result;
import com.ymm.lulutong.constant.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author guorui
 */
@Slf4j
@Service("shipperProfileDomainServiceImpl")
public class ShipperProfileDomainServiceImpl implements ShipperProfileDomainService {
    @Resource
    private ShipperProfileMapper shipperProfileMapper;

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    @Override
    public Result<Shipper> register(String phone, String password, String passwordValidate, String nickname) {
        if (phone == null || password == null || passwordValidate == null || nickname == null) {
            log.info("注册失败！传入参数错误！");
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        if (!FormatUtils.checkPhoneNumberFormat(phone)) {
            log.info("注册失败！手机号格式不规范！");
            return Result.fail(null, ProfileCodeEnum.PHONE_NUMBER_FORMAT_ERROR.getCode(), ProfileCodeEnum.PHONE_NUMBER_FORMAT_ERROR.getMessage());
        }
        if (!FormatUtils.checkPasswordFormat(password)) {
            log.info("注册失败！密码格式不规范！");
            return Result.fail(null, ProfileCodeEnum.PASSWORD_FORMAT_ERROR.getCode(), ProfileCodeEnum.PASSWORD_FORMAT_ERROR.getMessage());
        }
        if (!password.equals(passwordValidate)) {
            log.info("注册失败！两次密码不相同!");
            return Result.fail(null, ProfileCodeEnum.PASSWORD_NOT_CONSISTENT.getCode(), ProfileCodeEnum.PASSWORD_NOT_CONSISTENT.getMessage());
        }
        if (!FormatUtils.checkNicknameFormat(nickname)) {
            log.info("注册失败！昵称不规范！");
            return Result.fail(null, ProfileCodeEnum.NICKNAME_FORMAT_ERROR.getCode(), ProfileCodeEnum.NICKNAME_FORMAT_ERROR.getMessage());
        }
        Shipper shipper = new Shipper();
        try {
            if (shipperProfileMapper.existPhoneNumber(phone)) {
                log.info("注册失败！已被注册的手机号！");
                return Result.fail(null, ProfileCodeEnum.PHONE_NUMBER_REGISTERED.getCode(), ProfileCodeEnum.PHONE_NUMBER_REGISTERED.getMessage());
            }
            //密码加密
            password = EncryptionUtils.encryption(password);
            //设置货主初始信息
            shipper.setPhoneNumber(phone);
            shipper.setNickname(nickname);
            shipper.setPwd(password);
            shipper.setCreateTime(new Date());
            shipper.setUpdateTime(new Date());
            shipper.setValid(Boolean.TRUE);
            //设置货主钱包
            shipper.setTotalBalance(0);
            //设置货主会员信息
            shipper.setVipType(VIPCodeEnum.TYPE_COMMON.getCode());
            //初始设置100
            shipper.setVipScore(500);
            //插入货主表，自动在shipper中返回主键
            shipperProfileMapper.add(shipper);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("注册失败！服务器繁忙");
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
        log.info("注册成功");
        return Result.success(shipper);
    }

    @Override
    public Result<Shipper> login(String phone, String password) {
        if (password == null || phone == null) {
            log.info("登录失败！传入参数错误！" + password + phone);
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        Shipper shipper;
        try {
            shipper = shipperProfileMapper.selectByPhoneNumber(phone);
            if (shipper == null) {
                log.info("登录失败！不存在的手机号");
                return Result.fail(null, ProfileCodeEnum.PHONE_NUMBER_UNREGISTERD.getCode(), ProfileCodeEnum.PHONE_NUMBER_UNREGISTERD.getMessage());
            }
            if (!shipper.getValid()) {
                log.info("登录失败！已注销的手机号");
                return Result.fail(null, ProfileCodeEnum.ACCOUNT_CANCELLED.getCode(), ProfileCodeEnum.ACCOUNT_CANCELLED.getMessage());
            }
            password = EncryptionUtils.encryption(password);
            Result<Shipper> redisLoginResult = redisLogin(shipper, password);
            if (!redisLoginResult.getCode().equals(ResultCodeEnum.REDIS_ERROR.getCode())) {
                return redisLoginResult;
            }
            if (!password.equals(shipper.getPwd())) {
                log.info("登录失败！密码错误！");
                return Result.fail(null, ProfileCodeEnum.PASSWORD_INCORRECT.getCode(), ProfileCodeEnum.PASSWORD_INCORRECT.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("登录失败！服务器繁忙");
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
        log.info("登录成功");
        return Result.success(shipper);
    }

    @Override
    public Result<Shipper> updatePassword(Long shipperId, String newPassword, String newPasswordValidate) {
        if (shipperId == null || newPassword == null || newPasswordValidate == null) {
            log.info("修改密码失败！传入参数错误！");
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        if (!FormatUtils.checkPasswordFormat(newPassword)) {
            log.info("修改密码失败！密码格式不规范！");
            return Result.fail(null, ProfileCodeEnum.PASSWORD_FORMAT_ERROR.getCode(), ProfileCodeEnum.PASSWORD_FORMAT_ERROR.getMessage());
        }
        if (!newPassword.equals(newPasswordValidate)) {
            log.info("修改密码失败！两次密码不相同!");
            return Result.fail(null, ProfileCodeEnum.PASSWORD_NOT_CONSISTENT.getCode(), ProfileCodeEnum.PASSWORD_NOT_CONSISTENT.getMessage());
        }
        Shipper shipper;
        try {
            shipper = shipperProfileMapper.selectById(shipperId);
            if (shipper == null) {
                log.info("修改密码失败！不存在的用户");
                return Result.fail(null, ProfileCodeEnum.SHIPPER_NOT_EXIST.getCode(), ProfileCodeEnum.SHIPPER_NOT_EXIST.getMessage());
            }
            newPassword = EncryptionUtils.encryption(newPassword);
            if (newPassword.equals(shipper.getPwd())) {
                log.info("修改密码失败！与原先密码相同");
                return Result.fail(null, ProfileCodeEnum.PASSWORD_UNCHANGED.getCode(), ProfileCodeEnum.PASSWORD_UNCHANGED.getMessage());
            }
            Shipper shipperCondition = new Shipper();
            shipperCondition.setShipperId(shipperId);
            shipperCondition.setPwd(newPassword);
            shipperProfileMapper.updateByIdOnCondition(shipperCondition);
            shipper.setPwd(newPassword);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("修改密码失败！服务器繁忙");
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
        return Result.success(shipper);
    }

    @Override
    public Result<Shipper> retrievePassword(String phoneNumber, String newPassword, String newPasswordValidate) {
        if (phoneNumber == null || newPassword == null || newPasswordValidate == null) {
            log.info("找回密码失败！传入参数错误！");
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        if (!FormatUtils.checkPasswordFormat(newPassword)) {
            log.info("找回密码失败！密码格式不规范！");
            return Result.fail(null, ProfileCodeEnum.PASSWORD_FORMAT_ERROR.getCode(), ProfileCodeEnum.PASSWORD_FORMAT_ERROR.getMessage());
        }
        if (!newPassword.equals(newPasswordValidate)) {
            log.info("找回密码失败！两次密码不相同!");
            return Result.fail(null, ProfileCodeEnum.PASSWORD_NOT_CONSISTENT.getCode(), ProfileCodeEnum.PASSWORD_NOT_CONSISTENT.getMessage());
        }
        Shipper shipper;
        try {
            shipper = shipperProfileMapper.selectByPhoneNumber(phoneNumber);
            if (shipper == null) {
                log.info("找回密码失败！不存在的用户");
                return Result.fail(null, ProfileCodeEnum.SHIPPER_NOT_EXIST.getCode(), ProfileCodeEnum.SHIPPER_NOT_EXIST.getMessage());
            }
            newPassword = EncryptionUtils.encryption(newPassword);
            if (newPassword.equals(shipper.getPwd())) {
                log.info("找回密码失败！与原先密码相同");
                return Result.fail(null, ProfileCodeEnum.PASSWORD_UNCHANGED.getCode(), ProfileCodeEnum.PASSWORD_UNCHANGED.getMessage());
            }
            Shipper shipperCondition = new Shipper();
            shipperCondition.setShipperId(shipper.getShipperId());
            shipperCondition.setPwd(newPassword);
            shipperProfileMapper.updateByIdOnCondition(shipperCondition);
            shipper.setPwd(newPassword);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("找回密码失败！服务器繁忙");
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
        return Result.success(shipper);
    }

    @Override
    public Result<Shipper> updatePhoneNumber(Long shipperId, String newPhoneNumber) {
        if (shipperId == null || newPhoneNumber == null) {
            log.info("修改手机号失败！传入参数错误！");
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        if (!FormatUtils.checkPhoneNumberFormat(newPhoneNumber)) {
            log.info("修改手机号失败！手机号格式不规范！");
            return Result.fail(null, ProfileCodeEnum.PHONE_NUMBER_FORMAT_ERROR.getCode(), ProfileCodeEnum.PHONE_NUMBER_FORMAT_ERROR.getMessage());
        }
        Shipper shipper;
        try {
            if (shipperProfileMapper.existPhoneNumber(newPhoneNumber)) {
                log.info("修改手机号失败！手机号已被注册！");
                return Result.fail(null, ProfileCodeEnum.PHONE_NUMBER_REGISTERED.getCode(), ProfileCodeEnum.PHONE_NUMBER_REGISTERED.getMessage());
            }
            shipper = shipperProfileMapper.selectById(shipperId);
            if (shipper == null) {
                log.info("修改手机号失败！不存在的用户");
                return Result.fail(null, ProfileCodeEnum.SHIPPER_NOT_EXIST.getCode(), ProfileCodeEnum.SHIPPER_NOT_EXIST.getMessage());
            }
            if (newPhoneNumber.equals(shipper.getPhoneNumber())) {
                log.info("修改手机号失败！与原先手机号相同");
                return Result.fail(null, ProfileCodeEnum.PHONE_NUMBER_UNCHANGED.getCode(), ProfileCodeEnum.PHONE_NUMBER_UNCHANGED.getMessage());
            }
            Shipper shipperCondition = new Shipper();
            shipperCondition.setShipperId(shipperId);
            shipperCondition.setPhoneNumber(newPhoneNumber);
            shipperProfileMapper.updateByIdOnCondition(shipperCondition);
            shipper.setPhoneNumber(newPhoneNumber);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("修改手机号失败！服务器繁忙");
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
        return Result.success(shipper);
    }

    @Override
    public Result<Shipper> updateProfilePicture(Long shipperId, MultipartFile image) {
        if (shipperId == null || image == null) {
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), "入参错误");
        }
        //判断图片是否合法
        String fileName = image.getOriginalFilename();
        if (Objects.isNull(fileName)) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "参数错误");
        }
        int index = fileName.lastIndexOf(".");
        String suffix = fileName.substring(index);
        if (!".png".equals(suffix) && !".jpg".equals(suffix) && !".jpeg".equals(suffix)) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "请上传png/jpg/jpeg格式的图片文件！");
        }
        //确定文件存放路径
        String relativePath = "/img/avatar/" + shipperId + "/" + System.currentTimeMillis() + suffix;
        Shipper shipper = new Shipper();
        shipper.setShipperId(shipperId);
        shipper.setProfilePictureLink(relativePath);
        //存储文件
        try {
            Result<Boolean> uploadResult = UploadFileUtils.upload(image, relativePath);
            if (Objects.isNull(uploadResult)) {
                return Result.fail(null, ResultCodeEnum.FAIL.getCode(), "系统繁忙");
            }
            if (!uploadResult.isSuccess()) {
                return Result.fail(null, uploadResult.getCode(), uploadResult.getMessage());
            }
            shipperProfileMapper.updateByIdOnCondition(shipper);
            shipper = shipperProfileMapper.selectById(shipperId);
            return Result.success(shipper);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件存储失败" + e.getMessage());
            return Result.fail(null, ResultCodeEnum.FAIL.getCode(), "文件存储失败，服务器异常");
        }
    }

    @Override
    public Result<Shipper> getShipperByShipperId(Long shipperId) {
        Shipper shipper;
        try {
            shipper = shipperProfileMapper.selectById(shipperId);
            if (shipper == null) {
                log.info("不存在的用户 " + shipperId);
                return Result.fail(null, ProfileCodeEnum.SHIPPER_NOT_EXIST.getCode(), ProfileCodeEnum.SHIPPER_NOT_EXIST.getMessage());
            }
        } catch (Exception e) {
            log.error("服务器繁忙");
            e.printStackTrace();
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
        return Result.success(shipper);
    }

    @Override
    public Result<List<Shipper>> listShippersByPage(int pageNum, int pageSize) {
        if (pageNum < 0 || pageSize <= 0) {
            log.info("输入参数错误");
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), ResultCodeEnum.PARAM_ERROR.getMessage());
        }
        if (pageSize > 100) {
            log.info("页面记录数太大");
            return Result.fail(null, ResultCodeEnum.PAGESIZE_TOO_LARGE.getCode(), ResultCodeEnum.PAGESIZE_TOO_LARGE.getMessage());
        }
        try {
            int offset = pageNum * pageSize;
            List<Shipper> shippers = shipperProfileMapper.listAllByLimit(offset, pageSize);
            return Result.success(shippers);
        } catch (Exception e) {
            log.error("服务器繁忙");
            e.printStackTrace();
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
    }

    @Override
    public Result<List<Shipper>> listShippersOnConditionByPage(int pageNum, int pageSize, Shipper condition) {
        if (pageNum < 0 || pageSize <= 0) {
            log.info("输入参数错误");
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), ResultCodeEnum.PARAM_ERROR.getMessage());
        }
        if (pageSize > 100) {
            log.info("页面记录数太大");
            return Result.fail(null, ResultCodeEnum.PAGESIZE_TOO_LARGE.getCode(), ResultCodeEnum.PAGESIZE_TOO_LARGE.getMessage());
        }
        if (condition == null) {
            log.info("输入参数错误");
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        try {
            int offset = pageNum * pageSize;
            List<Shipper> shippers = shipperProfileMapper.listAllByLimitOnCondition(condition, offset, pageSize);
            return Result.success(shippers);
        } catch (Exception e) {
            log.error("服务器繁忙");
            e.printStackTrace();
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
    }

    @Override
    public Result<List<Shipper>> listShippersByShipperIds(List<Long> shipperIds) {
        if (shipperIds == null) {
            log.info("输入参数错误");
            return Result.fail(null, ResultCodeEnum.PARAMETER_NULL_ERROR.getCode(), ResultCodeEnum.PARAMETER_NULL_ERROR.getMessage());
        }
        if (shipperIds.size() > 100) {
            log.info("返回数据过多");
            return Result.fail(null, ResultCodeEnum.RETURN_DATA_TOO_MANY.getCode(), ResultCodeEnum.RETURN_DATA_TOO_MANY.getMessage());
        }
        try {
            List<Shipper> shippers = shipperProfileMapper.listByIds(shipperIds);
            return Result.success(shippers);
        } catch (Exception e) {
            log.info("服务器繁忙");
            e.printStackTrace();
            return Result.fail(null, ResultCodeEnum.DATABASE_ERROR.getCode(), ResultCodeEnum.DATABASE_ERROR.getMessage());
        }
    }

    /**
     * 登录时查看redis缓存，若用户登录手机号和密码不匹配超过三次，锁定5分钟
     *
     * @param shipper  货主实体
     * @param password 加密后的密码
     * @return 若为null，说明redis错误，需要查库返回
     */
    private Result<Shipper> redisLogin(Shipper shipper, String password) {
        try {
            String key = shipper.getShipperId().intValue() + "-loginTimes";
            Integer loginTimesInteger = redisTemplate.boundValueOps(key).get();
            int loginTimes = 0;
            if (!Objects.isNull(loginTimesInteger)) {
                loginTimes = loginTimesInteger;
            }
            if (loginTimes >= 3) {
                return Result.fail(null, ProfileCodeEnum.LOGIN_FAIL_MANY_TIMES.getCode(), ProfileCodeEnum.LOGIN_FAIL_MANY_TIMES.getMessage());
            }

            if (!password.equals(shipper.getPwd())) {
                log.info("登录失败！密码错误！");
                //三次后锁定5分钟
                loginTimes += 1;
                redisTemplate.boundValueOps(key).set(loginTimes, 5, TimeUnit.MINUTES);
                if (loginTimes >= 3) {
                    return Result.fail(null, ProfileCodeEnum.PASSWORD_INCORRECT.getCode(), "密码错误3次！锁定5分钟");
                } else {
                    return Result.fail(null, ProfileCodeEnum.PASSWORD_INCORRECT.getCode(), "密码错误，还有" + (3 - loginTimes) + "次机会");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.fail(null, ResultCodeEnum.REDIS_ERROR);
        }
        return Result.success(shipper);
    }
}
